home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (C) 1994, Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
- * the contents of this file may not be disclosed to third parties, copied or
- * duplicated in any form, in whole or in part, without the prior written
- * permission of Silicon Graphics, Inc.
- *
- * RESTRICTED RIGHTS LEGEND:
- * Use, duplication or disclosure by the Government is subject to restrictions
- * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
- * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
- * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
- * rights reserved under the Copyright Laws of the United States.
- */
- /*****************************************************************************
- *
- * Roland RAP-10 Music Card Device Driver for Eisa Bus
- * ---------------------------------------------------
- *
- * INTRODUCTION:
- * -------------
- * This file contains the device driver for Roland RAP-10
- * Music Card. Currently it contains necessary routines to Record and
- * Playback a Wave file. The MIDI Implementation is to be defined and
- * implemented at later time.
- *
- * DESIGN OVERVIEW:
- * ----------------
- * We will use DMA for wave data movements. At any given time, the card
- * can be either playing or recording and both operations are not allowed.
- * Also no more than one process at a time can access the card.
- *
- * Circular Buffers:
- * -----------------
- * Since DMA operation is performed independently of the processor,
- * we will buffer the user's data and release the user's process to
- * do other things (i.e. preparing more data). Internally we use a
- * circular queue (rwQue) to store the data to be played or recorded.
- * Each entry in this queue is of the type rwBuf_t where the data will
- * be stored. Each entry can store up to RW_BUF_SIZE bytes of data.
- * At the init time, we try to allocate two DMA channels for the card:
- * Channel 5 and 6. If we can only allocate Channel 5, we will use the
- * card in Mono mode, otherwise, we will use it as Stereo. DMA has two
- * buffers of its own: dmaRigh[] and dmaLeft[] for each Channel. For
- * Stereo play, the data user provides us is of the format:
- *
- * <Left Byte><Right Byte><Left Byte><Right Byte>.....
- * So for playing, we have to move all Left_Bytes to dmaLeft buffer
- * and all Right_Bytes to the dmaRight buffer (in Stereo mode only).
- * In mono mode, we will use dmaLeft[] buffer and all the user's data
- * are moved to dmaLeft[].
- *
- * The basic operation of the Card are as follow:
- *
- * Playing:
- * --------
- * For playing wave data, the user must first open the card through
- * open() system call.The call comes to us as rapopen(). This
- * routine resets all global values, states and counters, prepares
- * necessary DMA structures for each channel, disables RAP-10
- * interrupts and establishes this process as the owner of the card.
- *
- * The user provides us with the wave data by issuing write()
- * system calls. This call comes to us as rapwrite(). We will
- * move the data from user's address space into an empty rwQue[]
- * entry and will retrun so that the user can issue another call.
- * If there is no DMA going, we will start one and the data will
- * start to be moved to the Card to be played.
- * The user can issue as many write() as necessary. The playing
- * operation will be done by either closing the card or issuing
- * an Ioctl call. Issuing Ioctl, will leave this process as owner
- * still while closing the card will release the card.
- *
- * Recording:
- * ----------
- * Assuming that the user has opened the card and is the current
- * owner, user will issue read() system call. The call comes to
- * us as rapread(). If no DMA Record is going on, we will start
- * one. We will move data from rwQue[] entries (as they are filled)
- * to user's address space. The recording is done either by a
- * close() or ioctl() call.
- *
- *
- * DMA Starting:
- * -------------
- * For Playing, we will start DMA when we have a full circular buffer.
- * This is done so that we have enough data available for a fast DMA
- * operation to be busy with. For recording, we will start DMA
- * immediatly.
- *
- * Interrupts:
- * -----------
- * For each DMA transfer, we will receive two interrupts: One when 1st
- * half the buffer is transfered, one when 2nd half of the buffer is
- * transfered. We must fill the half that has just been transfered with
- * fresh data. Note that in Stereo mode, there are two DMA operation
- * going. So when we receive Interrupt for one DMA, we must wait for the
- * exact interrupt from the other DMA and service both DMA's half buffers.
- *
- * Card Address and IRQ
- * --------------------
- * We will use the default bus address of 0x330 and IRQ 5. Change in
- * bus address should also be reflected in /var/sysgen/system/rap.sm
- * file. Changes in IRQ should be reflected in the source code and
- * the program must be recomplied.
- *
- * ISSUES:
- * -------
- * 1. The DMA processing and transfer of data from/to user's buffer
- * are independent of each other. When we are servicing the
- * one half of the dma buffer that just been transfered, there is
- * no guarantee that we can fill that half of the buffer BEFORE
- * dma is done with the other half. In this case, dma plays the
- * fist half of buffer WHILE we are writing into it.
- *
- * 2. Currently eisa_dma_disable() routine does not actually
- * releases the Dma channels. This is the reason why we access
- * the Dma channel table (e_ch[]) ourselves and release the
- * channel.
- *
- * 3. Somehow because of number 2, the Play program cannot be
- * stopped with a Ctrl-C. In Play program this signal is
- * explicitly ignored. Trapping a Ctrl-C causes a kernel panic.
- * Once we have a workable eisa_dma_disable(), this problem will
- * be resolved.
- *
- *
- * TECHNICAL REFERENCES:
- * ---------------------
- * Roland RAP-10 Technical Reference and Programmer's Guide, Ver. 1.1
- * IRIX Device Driver Programming Guide
- * IRIX Device Driver Reference Pages.
- * Intel 82357 Preliminary Reference, Section: 3.7.8 Mode Register (pp: 223)
- *
- ******************************************************************************
- *** ***
- *** Copyright 1994, Silicon Graphics Inc., Mountain View, CA. ***
- *** ***
- ******************************************************************************
- */
-
-
- #include "sys/types.h"
- #include "sys/file.h"
- #include "sys/errno.h"
- #include "sys/open.h"
- #include "sys/conf.h"
- #include "sys/cmn_err.h"
- #include "sys/debug.h"
- #include "sys/param.h"
- #include "sys/edt.h"
- #include "sys/pio.h"
- #include "sys/uio.h"
- #include "sys/proc.h"
- #include "sys/user.h"
- #include "sys/eisa.h"
- #include "sys/sema.h"
- #include "sys/buf.h"
- #include "sys/cred.h"
- #include "sys/kmem.h"
- #include "sys/ddi.h"
-
- #include "./rap.h"
-
-
- /*
- * Macros to Read/Write 8 and 16-bit values from an address
- */
-
- #define OUTB(addr, b) ( *(volatile uchar_t *)(addr) = (b) )
- #define INPB(addr) ( *(volatile uchar_t *)(addr) )
- #define OUTW(addr, w) ( *(volatile ushort_t *)(addr) = (w) )
- #define INPW(addr) ( *(volatile ushort_t *)(addr) )
-
- /*
- * Raising and lowering CPU interrupt
- */
- #define LOCK() spl5();
- #define UNLOCK(s) splx(s);
- #define FROM_INTR 1
- #define FROM_USR 0
-
- #define User_pid u.u_procp->p_pid
-
- /*
- * IRQ and DMA channels we need.
- *
- */
- #define IRQ_MASK 0x0020
- #define DMAC_CH5 0x20 /* DMA Channel 5 */
- #define DMAC_CH6 0x40 /* DMA Channel 6 */
-
-
- /*=======================================*
- * MIDI and RAP Registers *
- *=======================================*
- *
- * The following is a description of RAP-10 registers. The same
- * names used throughout this program. Some of these registers are
- * 8-bit and some are 16-bit long.
- *
- * mdrd: MIDI Receive Data
- * mdtd: MIDI Transmit Data
- * mdst: MIDI Status
- * mdcm: MIDI Command
- * pwmd: Pulse Width Modulation Data
- * timm: Timer MSB data
- * gpcm: GPCC Command
- * dtci: DMA Transfer Count Buffer Interrupt Status
- * adcm: GPCC Analog to Digital Command
- * dacm: D/A Command and DMA Transfer Configuration
- * gpis: GPCC Interrupt Status
- * gpdi: GPCC DMA/Interrupt Enable
- * gpst: GPCC Status
- * dad0: Digital to Analog Data Channel 0
- * addt: A/D Data Transfer
- * dad1: Digital to Analog Data Channel 1
- * timd: Timer Data
- * cmp0: Compare Register Channel 0
- * dtcd: DMA Transfer Count Data
- * cmp1: Compare Register Channel 1
- *
- *
- * These defines indicate the offsets of the above registers
- * from the Drive's base address:
- */
-
- #define MDRD 0x0
- #define MDTD 0x0
- #define MDST 0x1
- #define MDCM 0x1
- #define PWMD 0x2
- #define TIMM 0x3
- #define GPCM 0x3
- #define DTCI 0x4
- #define ADCM 0x4
- #define DACM 0x5
- #define GPIS 0x6
- #define GPDI 0x6
- #define GPST 0x8
- #define DAD0 0x8
- #define ADDT 0xa
- #define DAD1 0xa
- #define TIMD 0xc
- #define CMP0 0xc
- #define DTCD 0xe
- #define CMP1 0xe
-
- typedef struct rapReg {
- uchar_t mdrd;
- uchar_t mdtd;
- uchar_t mdst;
- uchar_t mdcm;
- uchar_t pwmd;
- uchar_t timm;
- uchar_t gpcm;
- uchar_t dtci;
- uchar_t adcm;
- uchar_t dacm;
- ushort_t gpis;
- ushort_t gpdi;
- ushort_t gpst;
- ushort_t dad0;
- ushort_t addt;
- ushort_t dad1;
- ushort_t timd;
- ushort_t cmp0;
- ushort_t dtcd;
- ushort_t cmp1;
- } rapReg_t;
-
- /*==========================================================*
- * dtct (DMA Transfer Count) *
- *==========================================================*/
- #define DTCD_DRQ0 0x00FF /* DRQ 0 bits (0-7) */
- #define DTCD_DRQ1 0xFF00 /* DRQ 1 bits (8-15) */
-
-
-
- /*==========================================================*
- * gpst (GPCC Status) *
- *==========================================================*/
- #define GPST_PWM2 0x0800 /* PWM2 Busy (0=Write Enable, 1=Busy) */
- #define GPST_PWM1 0x0400 /* PWM1 Busy (0=Write Enable, 1=Busy) */
- #define GPST_PWM0 0x0200 /* PWM0 Busy (0=Write Enable, 1=Busy) */
- #define GPST_EPB 0x0100 /* EP Convertor Busy (0=Write Enable, 1=Busy) */
- #define GPST_GP1 0x0080 /* GP-chip, Ch 1 Acess (1 = Access) */
- #define GPST_GP0 0x0040 /* GP-chip, Ch 0 Acess (1 = Access) */
- #define GPST_MTE 0x0020 /* MIDI Tx Enable (0=Tx_Fifo buff full) */
- #define GPST_ORE 0x0010 /* MIDI Overrun Error (1 = error) */
- #define GPST_FE 0x0008 /* MIDI Framing Error (1 = error) */
- #define GPST_ADE 0x0004 /* A/D Error (1 = error) */
- #define GPST_DE1 0x0002 /* D/A Ch 1 Write Error (1 = error) */
- #define GPST_DE0 0x0001 /* D/A Ch 0 Write Error (1 = error) */
-
-
-
- /*==========================================================*
- * gpdi (GPCC DMA/Interrupt Enable (pp: 4-18) *
- *==========================================================*/
- #define GPDI_ITC 0x8000 /* DMA Transfer Cnt Match (0=Disable) */
- #define GPDI_DC2 0x4000 /* DMA Chann. Assignment, bit2 (pp:4-18) */
- #define GPDI_DC1 0x2000 /* DMA Chann. Assignment, bit1 (pp:4-18) */
- #define GPDI_DC0 0x1000 /* DMA Chann. Assignment, bit0 (pp:4-18) */
- #define GPDI_DT1 0x0800 /* DMA Trans. Mode, bit:1 (pp: 4-18) */
- #define GPDI_DT0 0x0400 /* DMA Trans. Mode, bit:0 (pp: 4-18) */
- #define GPDI_OVF 0x0200 /* Free Run.Cntr (FCR) Ov.Flow (0=Disable)*/
- #define GPDI_TC1 0x0100 /* Timer 1 Compare Match (0=Disable) */
- #define GPDI_TC0 0x0080 /* Timer 0 Compare Match (0=Disable) */
- #define GPDI_RXD 0x0040 /* MIDI Data Read Request (0=Disable) */
- #define GPDI_TXD 0x0020 /* MIDI Tx_fifo Buf Empty (0=Disable) */
- #define GPDI_ADD 0x0010 /* A/D Data Ready (0=Disable) */
- #define GPDI_DN1 0x0008 /* D/A Ch1 Note ON Ready (0=Disable) */
- #define GPDI_DN0 0x0004 /* D/A Ch0 Note ON Ready (0=Disable) */
- #define GPDI_DQ1 0x0002 /* D/A Ch1 Data Request (0=Disable) */
- #define GPDI_DQ0 0x0001 /* D/A Ch0 Data Request (0=Disable) */
-
-
-
- /*==========================================================*
- * gpis (GPCC Interrupt Status .. pp: 4-16) *
- *==========================================================*/
- #define GPIS_ITC 0x8000 /* DMA Transfer Count Match */
- #define GPIS_JSD 0x0400 /* Joystick Data Ready */
- #define GPIS_OVF 0x0200 /* Free Running Countr Overflow */
- #define GPIS_TC1 0x0100 /* Timer1 Compare Match */
- #define GPIS_TC0 0x0080 /* Timer0 Compare Match */
- #define GPIS_RXD 0x0040 /* MIDI Data Read Request */
- #define GPIS_TXD 0x0020 /* MIDI Tx_fifo Buf. Empty */
- #define GPIS_ADD 0x0010 /* A/D Data Ready */
- #define GPIS_DN1 0x0008 /* D/A Ch1 Note ON Ready */
- #define GPIS_DN0 0x0004 /* D/A Ch0 Note ON Ready */
- #define GPIS_DQ1 0x0002 /* D/A Ch1 Data Request */
- #define GPIS_DQ0 0x0001 /* D/A Ch0 Data Request */
-
-
- /*======================================================================*
- * dacm (Digital To Analogue Cmd and DMA Transfer Config) *
- *======================================================================*/
- #define DACM_SCC 0x80 /* DMA Size Cmp. Cnt (0=in Sample, 1=in Bytes)*/
- #define DACM_TS2 0x40 /* DMA Trnsfr Size, bit 2 (pp: 4-14) */
- #define DACM_TS1 0x20 /* DMA Trnsfr Size, bit 1 (pp: 4-14) */
- #define DACM_TS0 0x10 /* DMA Trnsfr Size, bit 0 (pp: 4-14) */
- #define DACM_DL1 0x08 /* Ch1 DA Data Len (0=8 bit, 1=17 bit) */
- #define DACM_DL0 0x04 /* Ch0 DA Data Len (0=8 bit, 1=17 bit) */
- #define DACM_DS1 0x02 /* Ch1 DA Convrsion (0=Stop, 1=Start) */
- #define DACM_DS0 0x01 /* Ch0 DA Convrsion (0=Stop, 1=Start) */
-
-
-
- /*=====================================================*
- * adcm ( GPCC AD Command ) *
- *=====================================================*/
- #define ADCM_MON 0x40 /* Monitor MIC (0=Monitor Off) */
- #define ADCM_GIN 0x20 /* Gain Input (0=Line, 1=Mic) */
- #define ADCM_AF1 0x10 /* Analog Freq Selection bit 1 (pp: 4-13)*/
- #define ADCM_AF0 0x08 /* Analog Freq Selection bit 0 (pp: 4-13)*/
- #define ADCM_ADL 0x04 /* Analog Data Length (0=8, 1=16)*/
- #define ADCM_ADM 0x02 /* Analog Data Conv. Mode (0=Mono,1=Stereo)*/
- #define ADCM_ADS 0x01 /* Analog Data Conv. Start(0=Stop,1=Start)*/
-
- /*=====================================================*
- * dtci ( DMA Trans.Count Buf Intr. Stat *
- *=====================================================*/
- #define DTCI_BF1 0x08 /* DMA DRQ1 buff full (1 = full) */
- #define DTCI_BH1 0x04 /* DMA DRQ1 buff half (1 = full) */
- #define DTCI_BF0 0x02 /* DMA DRQ0 buff full (1 = full) */
- #define DTCI_BH0 0x01 /* DMA DRQ0 buff half (1 = full) */
-
- /*========================================*
- * gpcm ( GPCC Command ) *
- *========================================*/
- #define GPCM_RST 0x80 /* Reset bit */
- #define GPCM_PWM2 0x10 /* Select PWM channel 2 */
- #define GPCM_PWM1 0x08 /* Select PWM channel 1 */
- #define GPCM_PWM0 0x04 /* Select PWM channel 0 */
- #define GPCM_FRCM 0x02 /* Free Run. Counter (1=Start) */
- #define GPCM_MTT 0x01 /* MIDI Timed Trans */
- /* ( 1 = Timer INT enabled ) */
-
- /*======================================*
- * timm (Timer MSB data) *
- *======================================*/
- #define TIMM_FRC 0x04 /* Free Running Counter Bit 16 */
- #define TIMM_CR1 0x02 /* Compare Reg 1 Bit 16 */
- #define TIMM_CR0 0x01 /* Compare Reg 0 Bit 16 */
-
- /*===================================*
- * mdcm (MIDI Command) *
- *===================================*/
- #define MDCM_UART 0x3f /* UART mode */
- #define MDCM_MPU 0xff /* MPU Reset */
- #define MDCM_VERSION 0xac /* Version */
- #define MDCM_REVISION 0xad /* Revision */
-
- /*===================================*
- * mdst (MIDI Status) *
- *===================================*/
- #define MDST_DSR 0x80 /* DSR = 0 if ready */
- #define MDST_DDR 0x40 /* DDR = 0 if ready */
-
- /*====================================*
- * RAP Card Info *
- *====================================*
- *
- * These are the information regarding the RAP Card.
- * The info being tracked are:
- *
- * ci_state: Our state (Installed, Opened, Playing, Recording)
- * ci_pid: PID of process opened us.
- * ci_addr[]: EISA Addresses
- * ci_irq: EISA Interrupt number we use
- * ci_ctl: Controller number we save from edt struct
- * ci_adap: Adaptor number we save from edt struct.
- * ci_dmaCh6: DMA Channel 6
- * ci_dmaCh5: DMA Channel 5
- * ci_dmaBuf6: EISA DMA Buffer struct for Channel 6
- * ci_dmaBuf5: EISA DMA Buffer struct for Channel 5
- * ci_dmaCb6: EISA DMA Control Block for Channel 6
- * ci_dmaCb5: EISA DMA Control Block for Channel 5
- *
- * di_state: DMA buffers state (Idle, Progress)
- * di_idx: Current rwQue[] entry being used.
- * di_ptr: Address in rwQue buffer
- * di_which: Which half of DMA buffer (0=1st half, 1=2nd Half)
- * di_bh: Total DMA Buffer Half (BH) Interrupt received.
- * di_bf: Total DMA Buffer Full (BF) Interrupt received.
- *
- * ri_state: State of Circular buffer (Wanted_Empty, etc.)
- * ri_free: Total Free entries in rwQue[]
- * ri_full: Total Full entries in rwQue[]
- * ri_idx: Current rwBuf for Read/Write
- * ri_tout; =1 if Timed out on read/write
- * ri_note; number of Note_On received
- * ri_ptr: Pointer in current rwBuf
- */
-
- typedef struct eisa_dma_buf dmaBuf_t;
- typedef struct eisa_dma_cb dmaCb_t;
-
- typedef struct cardInfo_s {
-
- /* Card Installation Info */
- ushort_t ci_state;
- pid_t ci_pid;
- caddr_t ci_addr[NBASE];
- int ci_irq;
- int ci_ctl;
- int ci_adap;
- int ci_dmaCh6;
- int ci_dmaCh5;
- dmaBuf_t *ci_dmaBuf6;
- dmaBuf_t *ci_dmaBuf5;
- dmaCb_t *ci_dmaCb6;
- dmaCb_t *ci_dmaCb5;
-
- /* DMA Buffer Information data */
- uchar_t di_state;
- short di_idx;
- uchar_t di_which;
- caddr_t di_ptr;
- uchar_t di_bh;
- uchar_t di_bf;
-
- /* Circular buffer Information data */
- uchar_t ri_state;
- short ri_free;
- short ri_full;
- short ri_idx;
- uchar_t ri_tout;
- uchar_t ri_note;
- caddr_t ri_ptr;
-
- } cardInfo_t;
-
- /* ci_state values */
- #define CARD_INSTALLED 0x0001
- #define CARD_STEREO 0x0002
- #define CARD_OPENED 0x0004
- #define CARD_PLAYING 0x0010
- #define CARD_RECORDING 0x0020
-
-
- /* di_state values */
- #define DI_DMA_IDLE 0x00
- #define DI_DMA_PLAYING 0x01
- #define DI_DMA_RECORDING 0x02
- #define DI_DMA_END_PLAY 0x04
- #define DI_DMA_END_RECORD 0x08
-
-
- /* ri_state values */
- #define RI_WANTED_EMPTY 0x01
-
- /*====================================*
- * Read/Write Circular Buffers *
- *====================================*
- *
- * This is the description of our circular buffers used
- * to store D/A and A/D values. D/A values are stored from
- * user's buffer and then moved to DMA buffers. A/D data is
- * moved from DMA buffers to these buffers and then moved
- * to user's buffer. The fields are as follow:
- *
- * rw_state: buffer state (Empty, Busy, Full)
- * rw_idx: Index of this buffer in rwQue[];
- * rw_count: Total bytes in the buffer
- * rw_buf[]: The buffer itself.
- *
- * RW_MIN_FULL: We will start a D/A DMA when we have this many
- * full buffer on hand. This is done so that we can
- * provide enough full buffers for DMA to process.
- */
-
- #define RW_BUF_SIZE 8192
- #define RW_BUF_COUNT 20
- #define RW_MIN_FULL 1
- #define RW_TIMEOUT 1600
-
- typedef struct rwBuf_s {
- uchar_t rw_state;
- short rw_idx;
- int rw_count;
- uchar_t rw_buf[RW_BUF_SIZE];
- } rwBuf_t;
-
- /* rw_state values */
- #define RW_EMPTY 0x00 /* used as parameter only */
- #define RW_FULL 0x01
- #define RW_WANTED_FULL 0x02
- #define RW_WANTED_EMPTY 0x04
-
-
- /*==================================*
- * Global values *
- *==================================*/
-
- #define DMA_BUF_SIZE 8192
- #define DMA_HALF_SIZE 4096
-
- int rapdevflag = 0;
- static cardInfo_t cardInfo;
- static caddr_t dmaRight;
- static caddr_t dmaLeft;
- static paddr_t dmaRightPhys;
- static paddr_t dmaLeftPhys;
- static rwBuf_t rwQue[RW_BUF_COUNT];
- static caddr_t eisa_addr;
-
- /*
- * Eisam Dma Channel semaphores..shoule be removed when
- * proper way of releasing channels found
- */
- extern struct eisa_ch_state {
- sema_t chan_sem; /* inuse semaphore for each channel */
- sema_t dma_sem; /* dma completion semaphore */
- struct eisa_dma_buf *cur_buf; /* current eisa_dma_buf being dma'ed */
- struct eisa_dma_cb *cur_cb; /* ptr to current command block */
- int count;
- } e_ch[];
-
-
- /*=========================================*
- * Driver Entry routines Data *
- *=========================================*/
-
- int rapopen ( dev_t *, int, int, cred_t * );
- int rapread ( dev_t, uio_t *, cred_t * );
- int rapwrite ( dev_t, uio_t *, cred_t * );
- int rapclose ( dev_t, int, int, cred_t * );
- void rapedtinit ( struct edt * );
- void rapintr ( int );
- int rapioctl (dev_t, int, void *, int, cred_t *, int *);
-
-
- /*=======================================*
- * Misc and Internal routines *
- *=======================================*/
-
- static void rapDisInt (cardInfo_t *);
- static int rapGetDma( dmaBuf_t **, dmaCb_t **, int );
- static int rapClose(uchar_t);
- static short rapGetNextEmpty (short, uchar_t);
- static short rapGetNextFull (short, uchar_t);
- static void rapPrepEisa( dmaBuf_t *, dmaCb_t *, uchar_t, paddr_t);
- static int rapStart(uchar_t);
- static void rapStop(uchar_t);
- static void rapStartDA();
- static void rapStartAD();
- static void rapBufToDma( int );
- static void rapDmaToBuf( int );
- static void rapMarkBuf(rwBuf_t *, cardInfo_t *, uchar_t);
- static int rapKernMem(uchar_t);
- static void rapSetAutoInit(cardInfo_t *, uchar_t);
- static void rapTimeOut( void *);
- static void rapNoteOn(cardInfo_t *, ushort_t );
- static void rapNoteOff(cardInfo_t *);
- static void rapZeroDma(cardInfo_t *, int);
- static void rapReleaseDma (cardInfo_t *);
-
-
-
-
- /*************************************************************************
- * r a p e d t i n i t
- *************************************************************************
- *
- * Name: rapedtint
- *
- * Purpose: Initializes the driver. Called once for each controller.
- * Called only once.
- *
- * Returns: None.
- *
- *************************************************************************/
-
- void
- rapedtinit ( struct edt *e )
- {
- int ctl, iospace, dmac, eirq;
- cardInfo_t *ci;
- piomap_t *pmap;
- iospace_t eisa_io;
-
-
- ci = &cardInfo;
-
- cmn_err (CE_NOTE, "rapedtinit: Installing RAP board.");
- bzero ((void *)ci, sizeof(cardInfo_t) );
- dmaRight = dmaLeft = (caddr_t)NULL;
- ci->ci_ctl = e->e_ctlr;
- ci->ci_adap = e->e_adap;
-
- /*
- * Get the base address of Eisa bus (for rapSetAutoInit)
- */
- bzero (&eisa_io, sizeof(iospace_t));
- eisa_io.ios_iopaddr = 0;
- eisa_io.ios_size = 1000;
-
- pmap = pio_mapalloc (e->e_bus_type, 0, &eisa_io, PIOMAP_FIXED, "eisa");
- if ( pmap == (piomap_t *)NULL ) {
- cmn_err (CE_WARN, "rapedtinit: Cannot get Eisa bus address");
- return;
- }
-
- eisa_addr = pio_mapaddr (pmap, eisa_io.ios_iopaddr);
-
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapedtinit: Eisa base address = %x", eisa_addr);
- #endif
-
- /*===================================================*
- * map EISA IO/Memory addresses for RAP-10 card *
- *===================================================*/
- for ( iospace = 0; iospace < NBASE; iospace++ ) {
-
- /* any address to map ? */
- if ( !e->e_space[iospace].ios_iopaddr )
- continue;
-
- pmap = pio_mapalloc ( e->e_bus_type, e->e_adap,
- &e->e_space[iospace],
- PIOMAP_FIXED, "rap10" );
-
- ci->ci_addr[iospace] = pio_mapaddr ( pmap,
- e->e_space[iospace].ios_iopaddr );
- }
-
- /* is Card still there ? */
- if ( badaddr(ci->ci_addr[0], 1) ) {
- cmn_err (CE_WARN, "rapedtinit: RAP board not installed.");
- return;
- }
-
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapedtinit: First Load..allocating IRQ");
- #endif
-
- eirq = eisa_ivec_alloc( e->e_adap, IRQ_MASK, EISA_EDGE_IRQ );
-
- if ( eirq < 0 ) {
- cmn_err (CE_WARN,
- "rapedtinit: Could not allocate IRQ for RAP card.");
- return;
- }
-
- /* set Interrupt handler */
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapedtinit: Setting Interrupt Handler for IRQ %d",
- eirq);
- #endif
-
- if ( eisa_ivec_set(e->e_adap, eirq, rapintr, e->e_ctlr) == -1 ) {
- cmn_err (CE_NOTE,
- "rapedtinit: Could not set Interrupt handler for Irq %d", eirq);
- ci->ci_state = 0;
- return;
- }
-
- ci->ci_irq = eirq;
-
-
- /*======================================*
- * DMA Channels Allocation *
- *======================================*/
-
- /* DMA channel 5 */
- dmac = eisa_dmachan_alloc ( e->e_adap, DMAC_CH5 );
- if ( dmac < 0 ) {
- cmn_err (CE_WARN,
- "rapedtinit: Could not allocate DMA Channel 5.");
- return;
- }
-
- ci->ci_dmaCh5 = dmac;
-
- /* DMA channel 6 */
- dmac = eisa_dmachan_alloc ( e->e_adap, DMAC_CH6 );
- if ( dmac < 0 ) {
- cmn_err (CE_WARN,
- "rapedtinit: Could not allocate DMA Chann 6.");
- cmn_err (CE_WARN,
- "rapedtinit: RAP is initialized as Mono.");
- }
- else {
- ci->ci_dmaCh6 = dmac;
- ci->ci_state |= CARD_STEREO;
- }
-
- /*==============================*
- * DMA Buffer allocation *
- *==============================*/
-
- if ( rapKernMem (1) ) {
- cmn_err (CE_WARN, "rapedtinit: Did not install RAP-10.");
- return;
- }
-
- ci->ci_state |= CARD_INSTALLED;
-
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapedtinit: RAP installed, Addr: %x, Irq: %d.",
- ci->ci_addr[0], ci->ci_irq );
-
- cmn_err (CE_NOTE, "rapedtinit: Init as %s, Dma 1 = %d, Dma 0 = %d",
- (ci->ci_state & CARD_STEREO ? "Stereo":"Mono"),
- ci->ci_dmaCh5, ci->ci_dmaCh6);
- #endif
-
- return;
-
- } /*** End rapedtinit ***/
-
-
-
- /*************************************************************************
- * r a p o p e n
- *************************************************************************
- *
- * Name: rapopen
- *
- * Purpose: Opens the RAP board and initializes necessary data
- *
- * Returns: 0 = Success, or appropriate error number.
- *
- *************************************************************************/
- int
- rapopen ( dev_t *dev, int oflag, int otyp, cred_t *cred)
- {
- register int i;
- cardInfo_t *ci;
- rwBuf_t *rw;
- dmaBuf_t *dmaB;
- dmaCb_t *dmaC;
-
-
- ci = &cardInfo;
-
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapopen: Opening, Addr = %x, ci_state = %x",
- ci->ci_addr[0], ci->ci_state );
- #endif
-
- /*
- * No card is installed or card is already opened
- */
- if ( !(ci->ci_state & CARD_INSTALLED) )
- return (ENODEV);
-
- if ( ci->ci_state & CARD_OPENED )
- return (EBUSY);
-
-
- /* Allocate DMA Buf and Cb for Channel 5 */
- if ( ci->ci_dmaBuf5 == (dmaBuf_t *)NULL ) {
- if ( rapGetDma(&dmaB, &dmaC, ci->ci_dmaCh5) ) {
- cmn_err (CE_WARN,
- "rapoen: Could not allocate DMA Buf 5.");
- return (ENOMEM);
- }
-
- ci->ci_dmaBuf5 = dmaB;
- ci->ci_dmaCb5 = dmaC;
- }
-
- /* if in stereo, do the same for Channel 6 */
- if ( ci->ci_state & CARD_STEREO ) {
- if ( rapGetDma(&dmaB, &dmaC, ci->ci_dmaCh6) ) {
- cmn_err (CE_WARN,
- "rapopen: Could not allocate DMA Buf 6.");
- return (ENOMEM);
- }
-
- ci->ci_dmaBuf6 = dmaB;
- ci->ci_dmaCb6 = dmaC;
- }
-
-
- /* Initialize Card Info structure */
- ci->ri_idx = 0;
- ci->di_idx = 0;
- ci->ri_state = 0;
- ci->di_state = 0;
- ci->di_ptr = 0;
- ci->ri_ptr = 0;
- ci->ri_free = RW_BUF_COUNT;
- ci->ri_full = 0;
-
- ci->ci_state &= ~(CARD_PLAYING | CARD_RECORDING );
-
- ci->ci_state |= CARD_OPENED;
- ci->ci_pid = User_pid;
-
- /* Initialize Circular Buffers */
- for ( i = 0; i < RW_BUF_COUNT; i++ ) {
- rw = &rwQue[i];
- rw->rw_count = 0;
- rw->rw_state = 0;
- rw->rw_idx = i;
- bzero (rw->rw_buf, RW_BUF_SIZE);
- }
-
-
- rapDisInt(ci);
-
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapopen: Opened succesfully");
- #endif
-
- return(0);
-
- } /*** End rapopen ***/
-
-
- /*************************************************************************
- * r a p w r i t e
- *************************************************************************
- *
- * Name: rapwrite
- *
- * Purpose: Write entry routine. This routine will transfer user's
- * data to current or an empty entry in rwQue[] and starts
- * DMA if none is going.
- *
- * Returns: 0 = Success, or errno
- *
- *************************************************************************/
- int
- rapwrite (dev_t dev, uio_t *uio, cred_t *cred)
- {
- cardInfo_t *ci;
- rwBuf_t *rw;
- toid_t to_id;
- int avail, size, totBytes, err, s;
-
- ci = &cardInfo;
-
- /*=========================*
- * Error Checking *
- *=========================*/
-
- /* no card is installed */
- if ( !(ci->ci_state & CARD_INSTALLED) )
- return (ENODEV);
-
- /* card is not opened */
- if ( !(ci->ci_state & CARD_OPENED) )
- return (EACCES);
-
- /* we are not the owner */
- if ( ci->ci_pid != User_pid )
- return (EACCES);
-
- /* is busy recording */
- if ( ci->ci_state & CARD_RECORDING )
- return (EACCES);
-
- ci->ci_state |= CARD_PLAYING;
- rw = &rwQue[ci->ri_idx];
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapwrite: %d bytes, buf = %d, rw_count = %d, free = %d, full = %d",
- uio->uio_resid, ci->ri_idx, rw->rw_count, ci->ri_free, ci->ri_full);
- #endif
-
-
- /* if it is full, wait till it is Empty */
- s = LOCK();
- if ( rw->rw_state & RW_FULL ) {
-
- ci->ri_ptr = NULL;
- ci->ri_tout = 0;
- to_id = itimeout (rapTimeOut, rw, RW_TIMEOUT, plbase, 0, 0, 0);
-
- while ( (rw->rw_state & RW_FULL) && !ci->ri_tout ) {
-
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapwrite: waiting for buf %d to be Empty",
- rw->rw_idx );
- #endif
-
- rw->rw_state |= RW_WANTED_EMPTY;
- if ( sleep (rw, PUSER | PCATCH) ) {
-
- untimeout(to_id);
-
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapwrite: Interrupted");
- #endif
-
- rw->rw_state &= ~RW_WANTED_EMPTY;
- UNLOCK(s);
- return (EINTR);
- }
-
- } /* while */
-
- untimeout(to_id);
-
-
- /* we timed out ..couldn't get the buffer */
- if ( ci->ri_tout ) {
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapwrite: Timed out");
- #endif
-
- rw->rw_state &= ~RW_WANTED_EMPTY;
- UNLOCK(s);
- return (EIO);
- }
-
-
- } /* if (rw->rw_state & RW_FULL */
-
- UNLOCK(s);
-
-
- /* adjuest the read/write address if necessary */
- if ( ci->ri_ptr == NULL )
- ci->ri_ptr = rw->rw_buf;
-
- totBytes = uio->uio_resid;
-
- while ( totBytes > 0 ) {
- avail = RW_BUF_SIZE - rw->rw_count;
-
- /* if this buffer is full, get next buffer */
- if ( avail <= 0 ) {
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapwrite: Buffer %d is Full now, rw_count = %d",
- rw->rw_idx, rw->rw_count);
- #endif
-
- s = LOCK();
- rapMarkBuf(rw, ci, RW_FULL);
-
- /* wake anyone wanted this buffer full */
- if ( rw->rw_state & RW_WANTED_FULL ) {
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapwrite: Buffer %d is Wanted_Full",
- rw->rw_idx );
- #endif
-
- rw->rw_state &= ~RW_WANTED_FULL;
- wakeup(rw);
- }
-
- /*
- * start DMA if none is going and we filled the
- * entire buffers.
- */
- if ( (ci->di_state == DI_DMA_IDLE) &&
- (rw->rw_idx >= RW_MIN_FULL ) ) {
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapwrite: Starting Play Dma");
- #endif
-
- err = rapStart(DI_DMA_PLAYING);
- if ( err ) {
- cmn_err (CE_WARN,
- "rapwrite: Could not start playing error %d", err );
- UNLOCK(s);
- return(err);
- }
- }
-
- /* get next empty buffer */
- ci->ri_idx = rapGetNextEmpty(ci->ri_idx, FROM_USR);
- rw = &rwQue[ci->ri_idx];
- ci->ri_ptr = rw->rw_buf;
- UNLOCK(s);
- continue;
- }
-
- /* start filling this buffer */
- size = (totBytes > avail ? avail: totBytes);
-
- err = uiomove (ci->ri_ptr, size, UIO_WRITE, uio);
- if ( err ) {
- cmn_err (CE_NOTE, "rapwrite: uiomov error %d", err);
- return(err);
- }
-
- rw->rw_count += size;
- ci->ri_ptr += size;
- totBytes = uio->uio_resid;
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapwrite: Wrote %d to Buffer %d, Left = %d, rw_count = %d",
- size, rw->rw_idx, totBytes, rw->rw_count );
- #endif
- }
-
- return (0);
-
- } /*** end rapwrite ***/
-
- /*************************************************************************
- * r a p r e a d
- *************************************************************************
- *
- * Name: rapread
- *
- * Purpose: Reads data from rwQue[] into user's buffer.
- * This routine waits for current DMA operation to end
- * and then starts a A/D Dma (recording). If A/D is already
- * going then it simply moves data from current Full buffer
- * into user's buffer. If buffer is not full, it waits for
- * it to get full.
- *
- * Returns: 0 = Success, or errno.
- *
- *************************************************************************/
- int
- rapread (dev_t dev, uio_t *uio, cred_t *cred)
- {
- cardInfo_t *ci;
- rwBuf_t *rw;
- toid_t to_id;
- int avail, size, totBytes, err, s;
-
- ci = &cardInfo;
-
- /*===============================*
- * Error Checking *
- *===============================*/
-
- /* card is not installed */
- if ( !(ci->ci_state & CARD_INSTALLED) )
- return (ENODEV);
-
- /* card is not opened */
- if ( !(ci->ci_state & CARD_OPENED) )
- return (EACCES);
-
- /* we do not own the card */
- if ( ci->ci_pid != User_pid )
- return (EACCES);
-
- /* card is in middle of a Play operation */
- if ( ci->ci_state & CARD_PLAYING )
- return (EIO);
-
- ci->ci_state |= CARD_RECORDING;
-
-
-
- /* start a A/D Dma if none is going on */
- if ( ci->di_state == DI_DMA_IDLE ) {
-
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapread: Idle DMA. Starting one");
- #endif
-
- if ( rapStart(DI_DMA_RECORDING) ) {
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapread: Could not start A/D");
- #endif
-
- ci->ci_state &= ~CARD_RECORDING;
- UNLOCK(s);
- return (EIO);
- }
- }
-
- /*
- * get the buffer we should be using and
- * wait for it to become Full
- */
- rw = &rwQue[ci->ri_idx];
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapread: %d bytes, buf = %d, rw_count = %d, free = %d, full = %d",
- uio->uio_resid, ci->ri_idx, rw->rw_count, ci->ri_free, ci->ri_full);
- #endif
-
- s = LOCK();
- if ( !(rw->rw_state & RW_FULL) ) {
-
- ci->ri_ptr = NULL;
- ci->ri_tout = 0;
- to_id = itimeout (rapTimeOut, rw, RW_TIMEOUT, plbase, 0, 0, 0);
-
- while ( !(rw->rw_state & RW_FULL) && !ci->ri_tout ) {
-
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapread: wating for buf %d to become Full",
- rw->rw_idx );
- #endif
-
- rw->rw_state |= RW_WANTED_FULL;
- if ( sleep (rw, PUSER | PCATCH) ) {
-
- untimeout (to_id);
-
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapread: Interrupted");
- #endif
-
- rw->rw_state &= ~RW_WANTED_FULL;
- UNLOCK(s);
- return(EINTR);
- }
-
- } /* while */
-
- untimeout (to_id);
-
- if ( ci->ri_tout ) {
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapread: Timed out");
- #endif
-
- rw->rw_state &= ~RW_WANTED_FULL;
- UNLOCK(s);
- return (EIO);
- }
-
- } /* if !rw->rw_state & RW_FULL */
-
- UNLOCK(s);
-
-
- /* adjust read/write pointer if necessary */
- if ( ci->ri_ptr == NULL )
- ci->ri_ptr = rw->rw_buf;
-
- /*===================================*
- * Actual Read (Data movement) *
- *===================================*/
- totBytes = uio->uio_resid;
-
- while ( totBytes > 0 ) {
- avail = rw->rw_count;
-
- /* if this buffer is Empty, get next Full buffer */
- if ( avail <= 0 ) {
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapread: Buffer %d is Empty now, rw_count = %d",
- rw->rw_idx, rw->rw_count );
- #endif
-
-
- s = LOCK();
- rapMarkBuf(rw, ci, RW_EMPTY);
-
- /* wake anyone wanted this buffer Empty */
- if ( rw->rw_state & RW_WANTED_EMPTY ) {
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapread: Buffer %d is Wanted_Empty",
- rw->rw_idx );
- #endif
-
- rw->rw_state &= ~RW_WANTED_FULL;
- wakeup(rw);
- }
-
- /* get next Full buffer */
- ci->ri_idx = rapGetNextFull(ci->ri_idx, FROM_USR);
- rw = &rwQue[ci->ri_idx];
- ci->ri_ptr = rw->rw_buf;
- UNLOCK(s);
- continue;
- }
-
- /* start filling this buffer */
- size = (totBytes > avail ? avail: totBytes);
-
- err = uiomove (ci->ri_ptr, size, UIO_READ, uio);
- if ( err ) {
- cmn_err (CE_PANIC, "rapread: uiomov error %d", err);
- return(err);
- }
-
- rw->rw_count -= size;
- ci->ri_ptr += size;
- totBytes = uio->uio_resid;
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapread: Read %d, Buffer %d, Left = %d, rw_count = %d",
- size, rw->rw_idx, totBytes, rw->rw_count );
- #endif
-
- }
-
- return (0);
-
- } /*** End rapread ***/
-
-
- /*************************************************************************
- * r a p c l o s e
- *************************************************************************
- *
- * Name: rapclose
- *
- * Purpose: closes connection to the card and makes it available
- * for next process to open it.
- *
- * Returns: 0 = Success, or errno
- *
- *************************************************************************/
- int
- rapclose (dev_t dev, int flag, int otyp, cred_t *cred)
- {
- cardInfo_t *ci;
-
- ci = &cardInfo;
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapclose: ci_state = %x, di_state = %x, full = %d, empty = %d",
- ci->ci_state, ci->di_state, ci->ri_full, ci->ri_free );
- #endif
-
- /*=========================*
- * Error Checking *
- *=========================*/
-
- /* card is not installed */
- if ( !(ci->ci_state & CARD_INSTALLED) )
- return (ENODEV);
-
- /* card is not opened */
- if ( !(ci->ci_state & CARD_OPENED) )
- return (EACCES);
-
- /* we do not own the card */
- if ( ci->ci_pid != User_pid )
- return (EACCES);
-
- return ( rapClose(1) );
- }
-
-
- /*************************************************************************
- * r a p i n t r
- *************************************************************************
- *
- * Name: rapintr
- *
- * Purpose: Interrupt handling routine
- *
- * Returns: None.
- *
- *************************************************************************/
- void
- rapintr ( int ctl )
- {
- ushort_t gpis;
- uchar_t dtci;
- uchar_t stereo;
- uchar_t totreq;
- uchar_t playing;
- uchar_t moveData;
- cardInfo_t *ci;
- caddr_t addr;
-
- ci = &cardInfo;
- addr = ci->ci_addr[0];
-
- /*
- * moveData: 0 = we should move data between Buf/DMA to DMA/Buf.
- * totreq: In stereo, we have to wait for 2 BF or BH interrupt
- * but in Mono we have to wait for only one.
- * playing: 1 = Playing, 0= Recording.
- */
- moveData = 0;
- totreq = (ci->ci_state & CARD_STEREO? 2:1); /* No. of Ints. we need */
- playing = ci->ci_state & CARD_PLAYING;
-
- gpis = INPW(addr+GPIS);
-
- /*
- * First, check for stray interrupts and ignore them
- */
- if ( !(ci->ci_state & (CARD_PLAYING | CARD_RECORDING)) ) {
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapintr: Stray interupt, gpis = %x, ci_state = %x",
- ci->ci_state );
- #endif
- return;
- }
-
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapintr: New ..Gpis = %x", gpis );
- #endif
-
-
- /**********************************
- * DMA Buffers Half/Full *
- **********************************/
- while ( gpis & GPIS_ITC ) {
-
- /* see which buffer is half/full */
- dtci = INPB(addr+DTCI);
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapintr: Dma buffer status..Gpis = %x, Dtci = %x", gpis, dtci);
- #endif
-
- if ( dtci & DTCI_BF0 )
- ci->di_bf++;
- if ( dtci & DTCI_BF1 )
- ci->di_bf++;
-
- if (dtci & DTCI_BH0 )
- ci->di_bh++;
- if (dtci & DTCI_BH1 )
- ci->di_bh++;
-
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapintr: di_bf = %d, di_bh = %d",
- ci->di_bf, ci->di_bh );
- #endif
-
- /* 1st half of dma needs service */
- if ( ci->di_bh == totreq ) {
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapintr: DMA First_Half needs service");
- #endif
-
- ci->di_bh = 0;
- ci->di_which = 0; /* 1st half of DMA buffer */
- moveData = 1;
- }
-
- /* 2nd half of dma needs service */
- else if ( ci->di_bf == totreq ) {
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapintr: DMA Second_Half needs service");
- #endif
-
- ci->di_bf = 0;
- ci->di_which = 1; /* 2nd half of DMA buffer */
- moveData = 1;
- }
-
- /*
- * Move data if needed
- */
- if ( moveData ) {
-
- /* move data for Play if only data available */
- if ( playing ) {
-
- /* No more data..end of play */
- if ( ci->ri_full <= 0 ) {
- if (ci->di_state & DI_DMA_END_PLAY ) {
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapintr: End of Play Reached");
- #endif
-
- if ( ci->ri_state & RI_WANTED_EMPTY ) {
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapintr: Cir.Buff is Wanted Empty");
- #endif
- ci->ri_state &= ~RI_WANTED_EMPTY;
- wakeup (ci);
- }
- else rapStop(DI_DMA_PLAYING);
-
- return;
- }
- else {
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapintr: Playing but no Full buffers");
- #endif
- return;
- }
-
- }
-
- /* Data is available to play */
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapintr: Playing..which = %d, idx = %d, full = %d, Empty = %d",
- ci->di_which, ci->di_idx, ci->ri_full, ci->ri_free);
- #endif
-
- rapBufToDma(DMA_HALF_SIZE);
-
- } /* if playing */
-
- else { /* recording */
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapintr: Recording..which = %d, full = %d, Empty = %d",
- ci->di_which, ci->ri_full, ci->ri_free);
- #endif
-
- rapDmaToBuf(DMA_HALF_SIZE);
-
- }
-
- } /* if move data */
-
- /* no need to move data */
- else {
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapintr: Waiting for next interrupt, bf = %d, bh = %d", ci->di_bf, ci->di_bh);
- #endif
- }
-
- gpis = INPW(addr+GPIS);
-
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapintr: next Gpis = %x", gpis);
- #endif
-
- } /* while ( gpis & .. */
-
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapintr: finished ...");
- #endif
-
- } /*** End rapintr ***/
-
-
- /*************************************************************************
- * r a p i o c t l
- *************************************************************************
- *
- * Name: rapioctl
- *
- * Purpose: handles IOCTL calls for RAP-10.
- *
- * Returns: 0 = Success, or errno
- *
- *************************************************************************/
- int
- rapioctl (dev_t dev, int cmd, void *arg, int mode, cred_t *cred, int *ret)
- {
- cardInfo_t *ci;
-
- ci = &cardInfo;
-
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapioctl: Cmd = %d, full = %d, Empty = %d",
- cmd, ci->ri_full, ci->ri_free );
- #endif
-
- /*
- * No card is installed or card is already opened
- */
- if ( !(ci->ci_state & CARD_INSTALLED) )
- return (ENODEV);
-
- if ( !(ci->ci_state & CARD_OPENED) )
- return (EACCES);
-
- if ( ci->ci_pid != User_pid )
- return (EACCES);
-
- *ret = 0;
-
- switch ( cmd ) {
- /*=======================*
- * End PLAY *
- *=======================*/
- case RAPIOCTL_END_PLAY:
- if ( !(ci->ci_state & CARD_PLAYING) ) {
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapioctl: End_PLay command in wrong state");
- #endif
- return (EACCES);
- }
-
- return (rapClose (0) );
-
- /*=======================*
- * End RECORD *
- *=======================*/
- case RAPIOCTL_END_RECORD:
- if ( !(ci->ci_state & CARD_RECORDING) ) {
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapioctl: End_Recrd command in wrong state");
- #endif
- return (EACCES);
- }
-
- return (rapClose (0) );
-
- } /* switch */
-
- return (0);
-
- } /** End rapioctl **/
-
-
- /****************************************************************************
- ****** I n t e r n a l R o u t i n e s *******
- ****************************************************************************/
-
-
- /*************************************************************************
- * r a p C l o s e
- *************************************************************************
- *
- * Name: rapClose
- *
- * Purpose: Routine to actually ends current operation and releases
- * the card. It is written as a separate routine here so
- * it can be shared by rapclose() and rapioctl() routines.
- * One frees up the card, one does not. Also if we are called
- * from ioctl, we will wait till all buffers are played (if
- * in Playback mode).
- *
- * Returns: 0 = Success, or errno
- *
- *************************************************************************/
-
- int
- rapClose( uchar_t relCard )
- {
-
- cardInfo_t *ci;
- rwBuf_t *rw;
- int s, totLeft;
-
- ci = &cardInfo;
-
- s = LOCK();
- rw = &rwQue[ci->ri_idx];
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapClose: relCard = %d, ci_state = %x, di_state = %x",
- relCard, ci->ci_state, ci->di_state );
- #endif
-
-
- /*
- * if we are not recording and are not playing
- * then simply mark the card as not opened and return
- */
- if ( !(ci->ci_state & (CARD_RECORDING | CARD_PLAYING)) ) {
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapClose: Idle card ..closing");
- #endif
-
- if ( relCard ) {
- ci->ci_state &= ~CARD_OPENED;
- ci->ci_pid = 0;
- }
- UNLOCK(s);
- return(0);
- }
-
-
- /*
- * Recording ? end it.
- */
- if ( ci->ci_state & CARD_RECORDING ) {
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapClose: Ending Record (A/D)");
- #endif
-
- rapStop(DI_DMA_RECORDING);
- if ( relCard ) {
- ci->ci_state &= ~CARD_OPENED;
- ci->ci_pid = 0;
- }
- UNLOCK(s);
- return(0);
- }
-
- /*
- * playback and called from close() routine ?
- * End the playback
- */
- if ( relCard ) {
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapClose: Ending Playback (D/A");
- #endif
-
- rapStop(DI_DMA_PLAYING);
- ci->ci_state &= ~CARD_OPENED;
- ci->ci_pid = 0;
- UNLOCK(s);
- return(0);
- }
-
- /*
- * Called from Ioctl.
- * Closing in middle of play is different based on we
- * have been called from close() routine or not.
- * If called from Ioctl (relCard = 0), we will wait till
- * all buffers are played back.
- */
- if ( !(rw->rw_state & RW_FULL) && (rw->rw_count > 0) ) {
-
- totLeft = RW_BUF_SIZE - rw->rw_count;
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapClose: Current Buf %d has %d data. Filled with %d zeros",
- rw->rw_idx, rw->rw_count, totLeft );
- #endif
-
- if ( totLeft > 0 ) {
- bzero (ci->ri_ptr, totLeft);
- ci->ri_ptr += totLeft;
- }
-
- rapMarkBuf(rw, ci, RW_FULL);
- }
-
- /* some buffers to play */
- if ( ci->ri_full > 0 ) {
-
- /* Playback has not started yet */
- if ( ci->di_state == DI_DMA_IDLE ) {
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapClose: Starting playback, full = %d, empty = %d",
- ci->ri_full, ci->ri_free);
- #endif
-
- rapStart(DI_DMA_PLAYING);
- }
-
- ci->di_state = DI_DMA_IDLE;
- ci->di_state |= DI_DMA_END_PLAY;
-
- /* wait till buffers are all played back */
- while ( ci->ri_full > 0 ) {
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapClose: waiting for Play to end..full = %d, empty = %d, ri_idx = %d, di_idx = %d",
- ci->ri_full, ci->ri_free, ci->ri_idx, ci->di_idx);
- #endif
-
- ci->ri_state |= RI_WANTED_EMPTY;
- if ( sleep (ci, PUSER | PCATCH) ) {
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapClose: Interrupted");
- #endif
-
- rapStop(DI_DMA_PLAYING);
- ci->ci_state &= ~CARD_OPENED;
- ci->ci_pid = 0;
- UNLOCK(s);
- return (EINTR);
- }
- }
-
- rapStop(DI_DMA_PLAYING);
-
- }
-
- else {
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapClose: Circular buffer empty..closing");
- #endif
-
- rapStop(DI_DMA_PLAYING);
- }
-
- UNLOCK(s);
-
- return(0);
-
- } /*** End rapClose ***/
-
- /*************************************************************************
- * r a p S t o p
- *************************************************************************
- *
- * Name: rapStop
- *
- * Purpose: Stops D/A and A/D conversion.
- *
- * Returns: None.
- *
- *************************************************************************/
- static void
- rapStop( uchar_t what )
- {
- cardInfo_t *ci;
- rwBuf_t *rw;
- caddr_t addr;
- uchar_t dacm, adcm;
- ushort_t gpdi;
- int s, i;
-
- s = LOCK();
-
- ci = &cardInfo;
- addr = ci->ci_addr[0];
-
- gpdi = adcm = dacm = 0;
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapStop: Stoping %s, full = %d, Empty = %d",
- (what == DI_DMA_PLAYING ? "Playback(D/A)":"Record(A/D)"),
- ci->ri_full, ci->ri_free);
- #endif
-
- switch ( what ) {
-
- /* stop D/A Conversion (Playing) */
- case DI_DMA_PLAYING:
- ci->di_which = 0;
- rapZeroDma(ci, DMA_BUF_SIZE);
- OUTB(addr+DACM, dacm);
- rapNoteOff (ci);
- break;
-
- /* stop A/D Conversion (recording) */
- case DI_DMA_RECORDING:
- OUTB(addr+ADCM, adcm);
- OUTB(addr+DACM, dacm);
- break;
- }
-
- OUTW(addr+GPDI, gpdi);
- rapReleaseDma(ci);
- /* Initialize Card Info structure */
- ci->ci_state &= ~(CARD_PLAYING | CARD_RECORDING);
- ci->ri_idx = 0;
- ci->di_idx = 0;
- ci->ri_state = 0;
- ci->di_state = 0;
- ci->di_ptr = rwQue[0].rw_buf;
- ci->ri_ptr = rwQue[0].rw_buf;
- ci->ri_free = RW_BUF_COUNT;
- ci->ri_full = 0;
-
- /* Initialize Circular Buffers */
- for ( i = 0; i < RW_BUF_COUNT; i++ ) {
- rw = &rwQue[i];
- rw->rw_count = 0;
- rw->rw_state = 0;
- rw->rw_idx = i;
- bzero (rw->rw_buf, RW_BUF_SIZE);
- }
-
- /* clear out any hanging GPIS and DACM */
- gpdi = INPW(addr+GPIS);
-
- UNLOCK(s);
-
- } /** End rapStop **/
-
-
-
- /*************************************************************************
- * r a p S t a r t
- *************************************************************************
- *
- * Name: rapStart
- *
- * Purpose: Prepares Eisa DMA buffers/Control block for Playing/Recording
- * This function is called when DMA is Idle.
- *
- * Returns: 0 = Success or Error number.
- *
- *************************************************************************/
-
- static int
- rapStart (uchar_t what)
- {
- cardInfo_t *ci;
- dmaBuf_t *dmaB;
- dmaCb_t *dmaC;
- uchar_t stereo;
- int err;
-
- ci = &cardInfo;
- stereo = (ci->ci_state & CARD_STEREO);
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapStart: Starting %s, full = %d, empty = %d",
- (what == DI_DMA_PLAYING ? "Playback(D/A)":"Record(A/D)"),
- ci->ri_full, ci->ri_free );
- #endif
-
- /* clear Dma buffers */
- ci->di_which = 0;
- rapZeroDma(ci, DMA_BUF_SIZE);
-
- /* check for Dma buffer addresses */
- if ( (ci->ci_dmaBuf5 == (dmaBuf_t *)0) ||
- (ci->ci_dmaCb5 == (dmaCb_t *)0) ) {
- cmn_err (CE_WARN,
- "rapStart: Chan 5 dmaBuf/dmaCb is NULL, what = %d", what);
- return(EIO);
- }
- if ( (ci->ci_dmaBuf6 == (dmaBuf_t *)0) ||
- (ci->ci_dmaCb6 == (dmaCb_t *)0) ) {
- cmn_err (CE_WARN,
- "rapStart: Chan 6 dmaBuf/dmaCb is NULL, what = %d", what);
- return(EIO);
- }
-
- /*
- * Prepare Eisa Buf and Cb for Channel 5. If in
- * stereo mode, do the same for Channel 6.
- */
- dmaB = ci->ci_dmaBuf5;
- dmaC = ci->ci_dmaCb5;
-
- rapPrepEisa (dmaB, dmaC, what, dmaLeftPhys );
-
- if ( stereo ) {
- dmaB = ci->ci_dmaBuf6;
- dmaC = ci->ci_dmaCb6;
- rapPrepEisa (dmaB, dmaC, what, dmaRightPhys );
- }
-
-
- /*
- * Program Eisa DMA Channels
- */
- err = eisa_dma_prog (ci->ci_adap, ci->ci_dmaCb5, ci->ci_dmaCh5,
- EISA_DMA_NOSLEEP);
-
- if ( err == 0 ) {
- cmn_err (CE_WARN, "rapStart: DMA Channel %d is busy",
- ci->ci_dmaCh5 );
- return (EBUSY);
- }
-
- if ( stereo ) {
- err = eisa_dma_prog (ci->ci_adap, ci->ci_dmaCb6, ci->ci_dmaCh6,
- EISA_DMA_NOSLEEP);
-
- if ( err == 0 ) {
- cmn_err (CE_WARN,
- "rapStart: DMA Channel %d is busy",
- ci->ci_dmaCh6 );
- return (EBUSY);
- }
- }
-
-
- /* enable hardware recognition on Eisa Dma Channels */
- eisa_dma_enable (ci->ci_adap, ci->ci_dmaCb5, ci->ci_dmaCh5,
- EISA_DMA_NOSLEEP);
-
- if ( stereo ) {
- eisa_dma_enable (ci->ci_adap, ci->ci_dmaCb6, ci->ci_dmaCh6,
- EISA_DMA_NOSLEEP);
-
- }
-
- /* set Eisa DMA register for Autoinit mode */
- rapSetAutoInit(ci, what);
-
- ci->di_state |= what;
-
- /* let's do it ! */
- if ( what == DI_DMA_PLAYING ) {
-
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapStart: Starting DMA for D/A Play");
- #endif
-
- rapStartDA();
- }
- else {
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapStart: Starting DMA for A/D Record");
- #endif
-
- rapStartAD();
- }
-
- return(0);
-
- } /** End rapStart **/
-
-
-
- /************************************************************************
- * r a p P r e p E i s a
- *************************************************************************
- *
- * Name: rapPrepEisa
- *
- * Purpose: prepares EISA Buf and Cb structures.
- *
- * Returns: None.
- *
- *************************************************************************/
- static void
- rapPrepEisa( dmaBuf_t *dmaB, dmaCb_t *dmaC, uchar_t what, paddr_t addr)
- {
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapPrepEisa: Preparing Eisa DMA buffers for %s",
- (what == DI_DMA_PLAYING ? "Playback(D/A)" : "Record(A/D)" ) );
- #endif
-
- /* prepare Eisa DMA Buf struct */
- bzero (dmaB, sizeof(dmaBuf_t) );
- dmaB->count = DMA_BUF_SIZE;
- dmaB->address = addr;
-
- /* prepare Eisa DMA Control Block */
- bzero (dmaC, sizeof(dmaCb_t) );
-
- dmaC->reqrbufs = dmaB;
- dmaC->reqr_path = EISA_DMA_PATH_16;
- dmaC->trans_type = EISA_DMA_TRANS_DMND;
- dmaC->targ_step = EISA_DMA_STEP_INC;
- dmaC->bufprocess = EISA_DMA_BUF_SNGL;
-
- if ( what == DI_DMA_PLAYING )
- dmaC->cb_cmd = EISA_DMA_CMD_READ; /* mem -> rap10 */
- else dmaC->cb_cmd = EISA_DMA_CMD_WRITE; /* rap10 -> mem */
-
- } /*** End rapPrepEisa ***/
-
-
- /*************************************************************************
- * r a p S t a r t D A
- *************************************************************************
- *
- * Name: rapStartDA
- *
- * Purpose: Enables appropriate RAP interrupts and starts D/A Dma.
- *
- * Returns: None
- *
- *************************************************************************/
- static void
- rapStartDA()
- {
- cardInfo_t *ci;
- caddr_t addr;
- ushort_t gpdi, gpis, gpst, dtcd, mask;
- uchar_t gpcm, pwmd, adcm, dacm;
- uchar_t stereo;
- int s;
-
- ci = &cardInfo;
- addr = ci->ci_addr[0];
-
- stereo = ci->ci_state & CARD_STEREO;
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapStartDA: Starting D/A Dma, full = %d, empty = %d",
- ci->ri_full, ci->ri_free );
- #endif
- /*
- * Prepare the board for Record (A/D)
- * Here is what we will do (in exact order):
- *
- * GPDI: Stereo = 0xA800, Mono = 0x9800
- * itc = 1, dma transfer match count
- * Stereo: Drq1->Dma5, Drq0->Dma6
- * Mono: Drq1->Dma5
- * Dt1, Dt0 = 10, Chan 1 ->Drq1, Chan 0 ->Drq0
- * Left Chan->Drq1, Right Chan->Drq0
- *
- *
- * DACM: Stereo: BF, Mono: BE
- * scc = 1, Dma size in byte
- * ts1 = ts2 = 1, transfer size of 4096 bytes
- * dl1 = dl0 = 1; Data length of 16 bits for both Channels.
- * Stereo ? ds1 = ds0 = 1 Start D/A on both Channels.
- * Mono ? ds1 = 1 Start D/A on Channel 1
- *
- * GPCM: Select Mike level = 0x04
- * Aux level = 0x08
- * PWMD: 0xFF (Max level)
- */
-
- gpdi = (stereo ? 0xA800: 0x9800);
- dacm = (stereo ? 0xBF:0xBE);
- gpcm = 0x04;
- pwmd = 0xFF;
- mask = (stereo ? (GPIS_DN1|GPIS_DN0): GPIS_DN1);
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapStartDA: gpdi = %x, dacm = %x", gpdi, dacm);
- #endif
-
- /* Set Rap-10 card */
- OUTB(addr+GPCM, gpcm);
- OUTB(addr+PWMD, pwmd);
- OUTW(addr+GPDI, gpdi);
- OUTB(addr+DACM, dacm);
-
- /*
- * Busy-wait for both Note_On interrupts
- * The interrupt version is commenetd out for now.
- */
- gpis = INPW(addr+GPIS);
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapStartDA: Waiting for Note_On, gpis = %x, mask = %x",
- gpis, mask);
- #endif
-
- while ( !(gpis & mask) ) {
- gpis = INPW(addr+GPIS);
-
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapStartDA: Waiting ..new gpis = %x", gpis);
- #endif
- }
-
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapStartDA: Note_On Interrupt Received, gpis = %x",
- gpis );
- #endif
-
- rapNoteOn(ci, gpis);
-
- } /*** End rapStartDA ***/
-
-
-
- /*************************************************************************
- * r a p S t a r t A D
- *************************************************************************
- *
- * Name: rapStartAD
- *
- * Purpose: Enables appropriate RAP interrupts and starts A/D Dma.
- *
- * Returns: None
- *
- *************************************************************************/
- static void
- rapStartAD()
- {
- cardInfo_t *ci;
- caddr_t addr;
- ushort_t gpdi;
- uchar_t gpcm, pwmd, adcm, dacm;
- uchar_t stereo, mic;
-
- ci = &cardInfo;
- addr = ci->ci_addr[0];
-
- stereo = ci->ci_state & CARD_STEREO;
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapStartAD: Starting A/D Dma in %s, full = %d, empty = %d",
- (stereo ? "Stereo":"Mono"), ci->ri_full, ci->ri_free );
- #endif
-
- /*
- * Prepare the board for Record (A/D)
- * Here is what we will do (in exact order):
- *
- * GPDI: Stereo = 0xA400, Mono = 0x9400
- * itc = 1, dma transfer match count
- * Stereo: Drq1->Dma5, Drq0->Dma6
- * Mono: Drq1->Dma5
- * Dt1, Dt0 = 01, Left Chan->Drq1, Right Chan->Drq0
- *
- *
- * DACM: 0xB0
- * scc = 1, Dma size in byte
- * ts1 = ts2 = 1, transfer size of 4096 bytes
- *
- *
- * GPCM: Select Mic level = 0x04
- * Aux level = 0x08
- * PWMD: 0xFF (Max level)
- *
- *
- * ADCM: Stereo: Mic 0x6F, line 0x4F,
- * Mono: Mic 0x6D, line 0x4D
- * Mon = 1, Monitor ON
- * Gin = 1, Head Amp Gain to Mic.
- * Af1, Af0 = 01, 22.05 KHz
- * Adl = 1, 16 bit data length
- * Stereo, Adm = 1, else = 0
- * Ads = 1, Start A/D
- */
-
- gpdi = (stereo ? 0xA400: 0x9400);
- gpcm = 0x08;
- adcm = (stereo ? 0x6F:0x6D);
- dacm = 0xB0;
- gpcm = 0x04;
- pwmd = 0xFF;
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapStartAD: Rap init as: gpdi = %x, dacm = %x, gpcm = %x, adcm = %x",
- gpdi, dacm, gpcm, adcm);
- #endif
-
- OUTW(addr+GPDI, gpdi);
- OUTB(addr+DACM, dacm);
- OUTB(addr+GPCM, gpcm);
- OUTB(addr+PWMD, pwmd);
- OUTB(addr+ADCM, adcm);
-
- } /*** End rapStartAD ***/
-
-
- /*************************************************************************
- * r a p B u f T o D m a
- *************************************************************************
- *
- * Name: rapBufToDma
- *
- * Purpose: moves data from current rwQue[] entry to DMA buffers.
- * This routine is called by INterrupt handler only except
- * once before we startd D/A (when no DMA is programmed yet)
- *
- * Returns: None
- *
- *************************************************************************/
- static void
- rapBufToDma( int bytes)
- {
- cardInfo_t *ci;
- rwBuf_t *rw;
- uchar_t *dmaR;
- uchar_t *dmaL;
- uchar_t stereo;
- int i, j, s;
-
- ci = &cardInfo;
- rw = &rwQue[ci->di_idx];
- stereo = ci->ci_state & CARD_STEREO;
-
- /*
- * filling 1st half or 2nd half of the buffers ?
- */
- if ( ci->di_which ) {
- dmaR = &dmaRight[DMA_HALF_SIZE];
- dmaL = &dmaLeft[DMA_HALF_SIZE];
- if ( bytes == DMA_BUF_SIZE ) {
- bytes = DMA_HALF_SIZE;
- }
- }
- /* filling 1st half of dma buffers */
- else {
- dmaR = &dmaRight[0];
- dmaL = &dmaLeft[0];
- }
-
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapBufToDma: Bytes = %d, which = %d, Idx = %d, rw_count = %d, Full = %d, Empty = %d",
- bytes, ci->di_which, ci->di_idx, rw->rw_count, ci->ri_full,
- ci->ri_free);
- #endif
-
- /*
- * if buffer is not Full, we zero out dma buffers and
- * return. We cannot wait till it gets Full.
- */
- if ( !(rw->rw_state & RW_FULL) ) {
-
- rapZeroDma(ci, bytes);
- ci->di_ptr = NULL;
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapBufToDma: Buf %d is not Full, rw_state = %x",
- rw->rw_idx, rw->rw_state );
- #endif
-
- return;
- }
-
- /* buffer is full of data ..readjust the buffer pointer */
- if ( ci->di_ptr == NULL )
- ci->di_ptr = rw->rw_buf;
-
- /*
- * Fill buffers ...
- */
- for ( i = 0; i < bytes; i++ ) {
-
- /*
- * First check if buffer is empty. If it is, mark it
- * as empty, wake anyone up who wants it and get the
- * next full buffer.
- */
- if ( rw->rw_count <= 0 ) {
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapBufToDma: Buf %d is Empty now, rw_count = %d",
- rw->rw_idx, rw->rw_count );
- #endif
-
- rapMarkBuf(rw, ci, RW_EMPTY);
- ci->di_ptr = NULL;
-
- if ( rw->rw_state & RW_WANTED_EMPTY ) {
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapBufToDma: Buf %d is Wanted_Empty",
- rw->rw_idx );
- #endif
-
- rw->rw_state &= ~RW_WANTED_EMPTY;
- wakeup(rw);
- }
-
- j = rapGetNextFull (ci->di_idx, FROM_INTR);
- if ( j == -1 ) {
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapBufToDma: Could not get next Full buffer");
- #endif
-
- break;
- }
-
- ci->di_idx = j;
- rw = &rwQue[ci->di_idx];
- ci->di_ptr = rw->rw_buf;
- continue;
- }
-
- /* buffer still has some data ..move them */
- if ( stereo ) {
- dmaL[i] = *(ci->di_ptr++);
- dmaR[i] = *(ci->di_ptr++);
- rw->rw_count -= 2;
- }
- else {
- dmaL[i] = *(ci->di_ptr++);
- rw->rw_count--;
- }
-
-
- } /* for .. */
-
- /* Flush the cache line so that Dma buffers contain all data */
- dki_dcache_wbinval (dmaL, (unsigned)bytes);
- if ( stereo )
- dki_dcache_wbinval (dmaR, (unsigned)bytes);
-
- } /*** end rapBufToDma ***/
-
-
- /*************************************************************************
- * r a p D m a T o B u f
- *************************************************************************
- *
- * Name: rapDmaToBuf
- *
- * Purpose: Moves data from DMA buffers (Right and Left in stereo)
- * into a rwQue entry. This routine is called only by
- * Interrupt Handler.
- *
- * Returns: None
- *
- *************************************************************************/
- static void
- rapDmaToBuf( int bytes)
- {
- cardInfo_t *ci;
- rwBuf_t *rw;
- uchar_t *dmaR;
- uchar_t *dmaL;
- uchar_t stereo;
- int i, j, s, inc;
-
- ci = &cardInfo;
- rw = &rwQue[ci->di_idx];
- stereo = ci->ci_state & CARD_STEREO;
-
- /*
- * filling 1st half or 2nd half of the buffers ?
- */
- if ( ci->di_which ) {
- dmaR = &dmaRight[DMA_HALF_SIZE];
- dmaL = &dmaLeft[DMA_HALF_SIZE];
- if ( bytes == DMA_BUF_SIZE ) {
- bytes = DMA_HALF_SIZE;
- }
- }
- /* filling 1st half of dma buffers */
- else {
- dmaR = &dmaRight[0];
- dmaL = &dmaLeft[0];
- }
-
- /* Invalidate the Cache */
- dki_dcache_inval (dmaL, (unsigned)bytes);
- if ( stereo )
- dki_dcache_inval (dmaR, (unsigned)bytes);
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapDmaToBuf: Bytes= %d, Idx = %d, rw_count = %d, Full = %d, Empty= %d",
- bytes, ci->di_idx, rw->rw_count, ci->ri_full, ci->ri_free);
- #endif
-
-
- /*
- * if buffer is Full ..we cannot wait ! Ignore new data
- * by simply returning.
- */
- if ( rw->rw_state & RW_FULL ) {
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapDmaToBuf: Buf %d is not Empty ..Ignoring data",
- rw->rw_idx );
- #endif
-
- return;
- }
-
- /* buffer is Empty ..calculate the end address */
- if ( ci->di_ptr == NULL )
- ci->di_ptr = rw->rw_buf;
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapDmaToBuf: Moving %s of DMA buffers in %s, rw_count = %x",
- (ci->di_which ? "Second Half" : "First Half"),
- (stereo ? "Stereo":"Monoe"), rw->rw_count);
- #endif
-
- /*
- * Fill buffers ...in stereo bytes are Left:Right:Left:Right...
- */
-
- for ( i = 0; i < bytes; i++ ) {
-
- /*
- * First check if this buffer is Full or not.
- * If it is, mark it as Full and wake anyone up who is
- * waiting for it. Then get the next Empty buffer.
- */
- if ( rw->rw_count >= RW_BUF_SIZE ) {
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapDmaToBuf: Buf %d is Full now, rw_count = %d",
- rw->rw_idx, rw->rw_count );
- #endif
-
- rapMarkBuf(rw, ci, RW_FULL);
-
- if ( rw->rw_state & RW_WANTED_FULL ) {
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapDmaToBuf: Buf %d is Wanted_Full",
- rw->rw_idx );
- #endif
-
- rw->rw_state &= ~RW_WANTED_FULL;
- wakeup(rw);
- }
-
- j = rapGetNextEmpty(ci->di_idx, FROM_INTR);
- if ( j == -1 ) {
- cmn_err (CE_NOTE,
- "rapDmaToBuf: Could not get next empty");
- return;
- }
- ci->di_idx = j;
- rw = &rwQue[ci->di_idx];
- ci->di_ptr = rw->rw_buf;
- continue;
- }
-
- /* buffer still has room ...move data */
- if ( stereo ) {
- *(ci->di_ptr++) = dmaL[i];
- *(ci->di_ptr++) = dmaR[i];
- rw->rw_count += 2;
-
- }
-
- else {
- *(ci->di_ptr++) = dmaL[i];
- rw->rw_count++;
- }
-
- } /* while bytes ... */
-
- } /*** end rapDmaToBuf ***/
-
-
-
-
- /*************************************************************************
- * r a p G e t N e x t F u l l
- *************************************************************************
- *
- * Name: rapGetNextFull
- *
- * Purpose: returns the index of next Full entry in rwQue[],
- * starting from a given index. Sleeps if the entry
- * is not Full.
- *
- * Returns: the index of the empty entry.
- *
- *************************************************************************/
- static short
- rapGetNextFull (short idx, uchar_t fromIntr)
- {
- cardInfo_t *ci;
- int s;
- toid_t to_id;
- rwBuf_t *rw;
-
- ci = &cardInfo;
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapGetNextFull: Getting Next Full Buffer..idx = %d, fromIntr: %d",
- idx, fromIntr );
- #endif
-
- /* go to beginning if at the end of the queu */
- idx++;
- if ( idx >= RW_BUF_COUNT )
- idx = 0;
-
-
- rw = &rwQue[idx];
-
- /*
- * if buffer is not available and we were called from Intrupt
- * handler, simply ignore the request and return error
- */
- s = LOCK();
- if ( !(rw->rw_state & RW_FULL) && (fromIntr) ) {
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapGetNextFull: Buffer %d is not Full. ..Cannot Wait",
- rw->rw_idx);
- #endif
-
- UNLOCK(s);
- return(-1);
- }
-
- /* wait for the buffer to become Full */
- if ( !(rw->rw_state & RW_FULL) ) {
-
- ci->ri_tout = 0;
- to_id = itimeout (rapTimeOut, rw, RW_TIMEOUT, plbase, 0, 0, 0);
- while ( !(rw->rw_state & RW_FULL) && !ci->ri_tout ) {
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapGetNextFull: Waiting for Buf %d to become Full",
- rw->rw_idx );
- #endif
-
- rw->rw_state |= RW_WANTED_FULL;
- if ( sleep(rw, PUSER | PCATCH) ) {
-
- untimeout(to_id);
-
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapGetNextFull: Interrupted");
- #endif
-
- rw->rw_state &= ~RW_WANTED_FULL;
- UNLOCK(s);
- return(-1);
- }
-
- }
- untimeout (to_id);
-
- if ( ci->ri_tout ) {
- #ifdef DEBUG
- cmn_err (CE_NOTE, "raGetNextFull: Timed out");
- #endif
-
- rw->rw_state &= ~RW_WANTED_FULL;
- UNLOCK(s);
- return (-1);
- }
-
-
- } /* if !(rw->rw_state & RW_FULL) */
-
- UNLOCK(s);
-
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapGetNextFull: next Full Buffer is %d", idx);
- #endif
-
- return(idx);
-
-
- } /*** End rapGetNextFull ***/
-
-
-
- /*************************************************************************
- * r a p G e t N e x t E m p t y
- *************************************************************************
- *
- * Name: rapGetNextEmpty
- *
- * Purpose: returns the index of next empty entry in rwQue[],
- * starting from a given index. Sleeps if the entry
- * is not empty.
- *
- * Returns: the index of the empty entry.
- *
- *************************************************************************/
- static short
- rapGetNextEmpty (short idx, uchar_t fromIntr)
- {
- cardInfo_t *ci;
- int s;
- toid_t to_id;
- rwBuf_t *rw;
-
-
- ci = &cardInfo;
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapGetNextEmpty: Getting Next Empty Buffer..idx = %d, fromIntr: %d",
- idx, fromIntr );
- #endif
-
- /* go to beginning if at the end of the queu */
- idx++;
- if ( idx >= RW_BUF_COUNT )
- idx = 0;
-
-
- rw = &rwQue[idx];
- s = LOCK();
-
- /*
- * if buffer is nit available and we were called from Intrupt
- * handler, simply ignore the request and return error
- */
- if ( (rw->rw_state & RW_FULL) && (fromIntr) ) {
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapGetNextEmpty: Buffer %d is not Empty ..Cannot Wait",
- rw->rw_idx);
- #endif
-
- UNLOCK(s);
- return(-1);
- }
-
- /* wait for the buffer to become Empty */
- if ( rw->rw_state & RW_FULL ) {
-
- ci->ri_tout = 0;
- to_id = itimeout (rapTimeOut, rw, RW_TIMEOUT, plbase, 0, 0, 0);
-
- while ( (rw->rw_state & RW_FULL) && !ci->ri_tout ) {
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapGetNextEmpty: Waiting for Buf %d to become Empty",
- rw->rw_idx );
- #endif
-
- rw->rw_state |= RW_WANTED_EMPTY;
- if ( sleep(rw, PUSER | PCATCH) ) {
-
- untimeout(to_id);
-
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapGetNextEmpty: Interrupted");
- #endif
-
- rw->rw_state &= ~RW_WANTED_EMPTY;
- UNLOCK(s);
- return(-1);
- }
-
- } /* while .. */
-
- untimeout (to_id);
-
- if ( ci->ri_tout ) {
- #ifdef DEBUG
- cmn_err (CE_NOTE, "raGetNextEmpty: Timed out");
- #endif
-
- rw->rw_state &= ~RW_WANTED_EMPTY;
- UNLOCK(s);
- return (-1);
- }
-
-
- } /* if (rw->rw_state & RW_FULL) */
-
- UNLOCK(s);
-
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapGetNextEmpty: next Empty Buffer is %d", idx);
- #endif
-
- return(idx);
-
- } /*** End rapGetNextEmpty ***/
-
-
- /*************************************************************************
- * r a p D i s I n t
- *************************************************************************
- *
- * Name: rapDisInt
- *
- * Purpose: Disables RAP-10 interrupts.
- *
- * Returns: None.
- *
- *************************************************************************/
- static void
- rapDisInt( cardInfo_t *ci)
- {
- caddr_t addr;
- ushort_t s;
- uchar_t c;
-
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapDisInt: full = %d, empty = %d, di_state = %d",
- ci->ri_full, ci->ri_free, ci->di_state );
- #endif
-
- addr = ci->ci_addr[0];
-
- /* disable all Interrupts */
- s = 0;
- OUTW(addr+GPDI, s);
- OUTB(addr+DACM, 0x00);
- OUTB(addr+ADCM, 0x00);
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapDisInt: Rap is set");
- #endif
-
- } /*** End rapDisInt ***/
-
-
- /**************************************************************************
- * r a p G e t D m a *
- **************************************************************************
- *
- * Name: rapGetDma
- *
- * Purpose: allocates dma Buf and Cb structures
- *
- * Returns: 0 = Success, 1 = Error
- *
- **************************************************************************/
-
- static int
- rapGetDma ( dmaBuf_t **dmaB, dmaCb_t **dmaC, int ch )
- {
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapGetDma: Getting Eisa Dma Buf and Cb for Channel %d", ch);
- #endif
-
- *dmaB = eisa_dma_get_buf (EISA_DMA_SLEEP);
- if ( *dmaB == NULL )
- return (1);
-
- *dmaC = eisa_dma_get_cb ( EISA_DMA_SLEEP );
- if ( *dmaC == NULL )
- return (1);
-
- return (0);
-
- } /*** End rapGetDma ***/
-
-
-
- /*************************************************************************
- * r a p M a r k B u f
- *************************************************************************
- *
- * Name: rapMarkBuf
- *
- * Purpose: Marks a buffer (Empty, Busy, Full) and increments/decrements
- * appropriate counters. Buffers status changed as:
- * Empty -> Busy -> Full -> Empty -> Busy ..
- *
- * Returns: None.
- *
- *************************************************************************/
- static void
- rapMarkBuf (rwBuf_t *rw, cardInfo_t *ci, uchar_t m)
- {
- int s;
-
- s = LOCK();
-
- switch ( m ) {
- case RW_EMPTY:
-
- rw->rw_state &= ~RW_FULL;
-
- if ( ci->ri_full )
- ci->ri_full--;
-
- ci->ri_free++;
- rw->rw_count = 0;
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapMarkBuf: Buf %d set EMPTY. Full = %d, Emp = %d",
- rw->rw_idx, ci->ri_full, ci->ri_free );
- #endif
-
- break;
-
- case RW_FULL:
-
- rw->rw_state |= RW_FULL;
- ci->ri_full++;
- if ( ci->ri_free )
- ci->ri_free--;
- rw->rw_count = RW_BUF_SIZE;
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapMarkBuf: Buf %d set FULL. Full = %d, Emp = %d",
- rw->rw_idx, ci->ri_full, ci->ri_free );
- #endif
-
- break;
- }
-
- UNLOCK(s);
-
- } /*** End rapMarkBuf ***/
-
-
- /*************************************************************************
- * r a p K e r n M e m
- *************************************************************************
- *
- * Name: rapKernMem
- *
- * Purpose: Allocates/Disallocates Kernel memory for Right and
- * Left DMA channels.
- *
- * Returns: 0 = Success, 1 = Failure.
- *
- *************************************************************************/
- static int
- rapKernMem ( uchar_t what)
- {
-
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapKernMem: %s Kernel Contigious Memory",
- (what == 1 ? "Allocating" : "Deallocating") );
- #endif
-
- switch ( what ) {
-
- /*=======================================*
- * Allocate Right/Left DMA Channels *
- *=======================================*/
- case 1:
- dmaRight = kmem_alloc (DMA_BUF_SIZE,
- KM_NOSLEEP | KM_PHYSCONTIG | KM_CACHEALIGN );
-
- if ( dmaRight == (caddr_t)NULL ) {
- cmn_err (CE_WARN,
- "rapKernMem: Cannot allocate DMA memory for R_chann");
- return(1);
- }
-
- dmaLeft = kmem_alloc (DMA_BUF_SIZE,
- KM_NOSLEEP | KM_PHYSCONTIG | KM_CACHEALIGN );
- if ( dmaLeft == (caddr_t)NULL ) {
- cmn_err (CE_WARN,
- "rapKernMem: Cannot allocate DMA memory for L_chann");
- kmem_free (dmaRight, DMA_BUF_SIZE);
- return(1);
- }
-
- /* get the physicall address */
- dmaRightPhys = kvtophys(dmaRight);
- dmaLeftPhys = kvtophys(dmaLeft);
-
- return(0);
-
- /*=======================================*
- * Deallocate Right/Left DMA Channels *
- *=======================================*/
- case 2:
- if ( dmaRight != NULL ) {
- kmem_free (dmaRight, DMA_BUF_SIZE);
- dmaRight = (caddr_t)NULL;
- }
- if ( dmaLeft != NULL ) {
- kmem_free (dmaLeft, DMA_BUF_SIZE);
- dmaLeft = (caddr_t)NULL;
- }
-
- return(0);
-
- } /* switch */
-
-
- } /*** End rapKernMem ***/
-
-
- /*************************************************************************
- * r a p T i m e O u t
- *************************************************************************
- *
- * Name: rapTimeOut
- *
- * Purpose: is called when Read/Write waiting for buffers time out.
- *
- * Returns:
- *
- *************************************************************************/
- static void
- rapTimeOut( void *addr )
- {
- cardInfo_t *ci;
-
- ci = &cardInfo;
-
- /* indicate a timeout */
- ci->ri_tout = 1;
- wakeup (addr);
-
- }
-
-
- /*************************************************************************
- * r a p N o t e O n
- *************************************************************************
- *
- * Name: rapNoteOn
- *
- * Purpose: Sends a MIDI Note_On message.
- * This code is taken from RAP-10 manual.
- *
- * Returns: None.
- *
- *************************************************************************/
- static void
- rapNoteOn ( cardInfo_t *ci, ushort_t orig_gpis)
- {
- int s, stereo;
- uchar_t c, pan, rank, chksum, sum;
- caddr_t addr;
- ushort_t gpis;
-
- addr = ci->ci_addr[0];
- stereo = ci->ci_state & CARD_STEREO;
- pan = 0x40;
- rank = 0x01; /* for 22050 Hz */
- gpis = orig_gpis;
-
- /*
- * Busy wait till Txd Fifo is empty
- * The interrupt version is commenetd out below
- */
-
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapNoteOn: Waiting for Txd Fifo Empty, gpis = %x",
- gpis);
- #endif
-
- while ( !(gpis & GPIS_TXD) ) {
- gpis = INPW(addr+GPIS);
-
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapNoteOn: Waiting ..new gpis = %x", gpis);
- #endif
- }
-
-
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapNoteOn: Issuing a Note_On SysEx Cmd");
- #endif
-
- /* send Note_On */
- c = 0xf0; OUTB(addr+MDTD, c);
- c = 0x41; OUTB(addr+MDTD, c);
- c = 0x10; OUTB(addr+MDTD, c);
- c = 0x56; OUTB(addr+MDTD, c);
- c = 0x12; OUTB(addr+MDTD, c);
-
- if ( stereo ) {
- c = 0x03; OUTB(addr+MDTD, c);
- c = 0x00; OUTB(addr+MDTD, c);
- c = 0x01; OUTB(addr+MDTD, c);
- sum = 0x03 + 0x01;
- }
- else {
- c = 0x02; OUTB(addr+MDTD, c);
- c = 0x00; OUTB(addr+MDTD, c);
- c = 0x0A+0x01; OUTB(addr+MDTD, c);
- sum = 0x02+0x0A+0x01;
- }
-
- c = 0x01; OUTB(addr+MDTD, c);
- c = 0x7F; OUTB(addr+MDTD, c);
- c = 0x7F; OUTB(addr+MDTD, c);
- OUTB(addr+MDTD, rank);
- sum += (0x01+0x7F+0x7F+rank);
-
- c = 0x40; OUTB(addr+MDTD, c);
- c = 0x00; OUTB(addr+MDTD, c);
- c = 0x40; OUTB(addr+MDTD, c);
- OUTB(addr+MDTD, pan);
- sum += (0x40+0x40+pan);
-
- /* calculate the checksum */
- chksum = (0x80 - (sum % 0x80)) & 0x7F;
- OUTB(addr+MDTD, chksum);
- c = 0xF7; OUTB(addr+MDTD, c);
-
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapNoteOn: Note_On Issued, chksum = %x", chksum);
- #endif
-
- } /* end rapNoteOn */
-
- /*************************************************************************
- * r a p N o t e O f f
- *************************************************************************
- *
- * Name: rapNoteOff
- *
- * Purpose: Sends a MIDI Note_Off message.
- * This code is taken from RAP-10 manual.
- *
- * Returns: None.
- *
- *************************************************************************/
- static void
- rapNoteOff ( cardInfo_t *ci)
- {
- int s, stereo;
- uchar_t pan, b, rank, sum, chksum;
- caddr_t addr;
- ushort_t gpis;
-
- addr = ci->ci_addr[0];
- stereo = ci->ci_state & CARD_STEREO;
- pan = 0x40;
- rank = 0x01; /* for 22050 Hz */
-
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapNoteOff: Waiting for Txd Empty");
- #endif
-
- /* wait till Txd is Empty */
- gpis = INPW(addr+GPIS);
- while ( !(gpis & GPIS_TXD) ) {
- us_delay(10);
- gpis = INPW(addr+GPIS);
-
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapNoteOff: Waiting ..new gpis = %x", gpis);
- #endif
-
- }
-
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapNoteOff: Issuing Note_Off");
- #endif
-
- /* send Note_On */
- OUTB(addr+MDTD, 0xF0);
- OUTB(addr+MDTD, 0x41);
- OUTB(addr+MDTD, 0x10);
- OUTB(addr+MDTD, 0x56);
- OUTB(addr+MDTD, 0x12);
-
- if ( stereo ) {
- OUTB(addr+MDTD, 0x03);
- OUTB(addr+MDTD, 0x00);
- OUTB(addr+MDTD, 0x01);
- sum = 0x03 + 0x01;
- }
- else {
- OUTB(addr+MDTD, 0x02);
- OUTB(addr+MDTD, 0x00);
- OUTB(addr+MDTD, 0x0A+0x01);
- sum = 0x02 + 0x0A + 0x01;
- }
-
- OUTB(addr+MDTD, 0x00);
- OUTB(addr+MDTD, 0x7F);
- OUTB(addr+MDTD, 0x7F);
- OUTB(addr+MDTD, 0x00);
- sum += 0x7F + 0x7F;
-
- OUTB(addr+MDTD, 0x40);
- OUTB(addr+MDTD, 0x00);
- OUTB(addr+MDTD, 0x40);
- OUTB(addr+MDTD, pan);
- sum += 0x40 + 0x40 + pan;
-
- /* calculate checksum */
- /* calculate the checksum */
- chksum = (0x80 - (sum % 0x80)) & 0x7F;
- OUTB(addr+MDTD, chksum);
- OUTB(addr+MDTD, 0x7F);
-
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapNoteOff: Note_On Issued, chksum = %x", chksum);
- #endif
-
- } /* end rapNoteOff */
-
- /*************************************************************************
- * r a p Z e r o D m a
- *************************************************************************
- *
- * Name: rapZeroDma
- *
- * Purpose: Zero outs DMA buffers.
- *
- * Returns: None.
- *
- *************************************************************************/
- static void
- rapZeroDma (cardInfo_t *ci, int bytes)
- {
-
- caddr_t dmaL, dmaR;
- int stereo, s;
-
- s = LOCK();
-
- stereo = ci->ci_state & CARD_STEREO;
-
-
- /*
- * Zero out which half ?
- */
- if ( ci->di_which ) {
- dmaR = &dmaRight[DMA_HALF_SIZE];
- dmaL = &dmaLeft[DMA_HALF_SIZE];
- if ( bytes == DMA_BUF_SIZE ) {
- bytes = DMA_HALF_SIZE;
- }
- }
- /* Zer out 1st half of dma buffers */
- else {
- dmaR = &dmaRight[0];
- dmaL = &dmaLeft[0];
- }
-
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapZeroDma: Zeroing out %s of Dma buffers in %s for %d bytes",
- (ci->di_which ? "2nd half":"1st half"),
- (stereo ? "Stereo":"Mono"),
- bytes);
- #endif
-
- bzero (dmaL, bytes);
- dki_dcache_wbinval (dmaL, (unsigned)bytes);
-
- if ( stereo ) {
- bzero (dmaR, bytes);
- dki_dcache_wbinval (dmaR, (unsigned)bytes);
- }
-
- UNLOCK(s);
- }
-
- /*************************************************************************
- * r a p R e l e a s e D m a
- *************************************************************************
- *
- * Name: rapReleaseDma
- *
- * Purpose: Releases Dma channel(s).
- * Note that we access kernel's Dma structure and later on
- * a routine will be provided for us to avoid this.
- *
- * Returns: None.
- *
- *************************************************************************/
- static void
- rapReleaseDma (cardInfo_t *ci)
- {
-
-
- /* disable Eisa Dma */
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapReleaseDma: Releasing Eisa Dma Chann %d",
- ci->ci_dmaCh5);
- #endif
-
- /* eisa_dma_disable(0, ci->ci_dmaCh5); */
- vsema(&e_ch[ci->ci_dmaCh5].chan_sem);
-
- if ( ci->ci_state & CARD_STEREO ) {
- #ifdef DEBUG
- cmn_err (CE_NOTE, "rapReleaseDma: Releasing Eisa Dma Chann %d",
- ci->ci_dmaCh6);
- #endif
-
- /* eisa_dma_disable(0, ci->ci_dmaCh6); */
- vsema (&e_ch[ci->ci_dmaCh6].chan_sem);
- }
-
- }
-
- /*************************************************************************
- * r a p S e t A u t o I n i t
- *************************************************************************
- *
- * Name: rapSetAutoInit
- *
- * Purpose: sets Eisa DMA register for Autoinit. In Autoinit, DMA
- * starts over from the beginning of the buffer again once it
- * has transfered all bytes in the buffer.
- *
- * Returns: None.
- *
- *************************************************************************/
- #define EISA_MODE_REG 0xd6
- #define EISA_CH5 0x01
- #define EISA_CH6 0x02
- #define EISA_WRITE 0x04
- #define EISA_READ 0x08
- #define EISA_AUTO 0x10
-
- static void
- rapSetAutoInit( cardInfo_t *ci, uchar_t what)
- {
- uchar_t b;
-
- #ifdef DEBUG
- cmn_err (CE_NOTE,
- "rapSetAutoInit: setting Autoinit DMA for %s, Eisa Addr = %x",
- ( what == DI_DMA_PLAYING ? "Playback(D/A)" : "Record(A/D)" ),
- eisa_addr );
- #endif
-
-
- b = 0;
- if ( what == DI_DMA_PLAYING )
- b |= EISA_READ; /* Memory -> Device */
- else b |= EISA_WRITE; /* Device -> Memory */
-
- /* Autoinit for Channel 5 - Demand Mode select is default */
- b |= (EISA_AUTO | EISA_CH5);
- OUTB(eisa_addr+EISA_MODE_REG, b);
-
-
- /* Autoinit for Channel 6 (if in stereo mode) */
- if ( ci->ci_state & CARD_STEREO ) {
- b &= ~EISA_CH5;
- b |= EISA_CH6;
- OUTB(eisa_addr+EISA_MODE_REG, b);
- }
-
-
- } /*** End rapSetAutoInit ***/
-
-